package whackEm.V2;

import java.util.ArrayList;
import java.util.Random;

import whackEm.V2.R;
import whackEm.elements.BlueClock;
import whackEm.elements.Mole;
import whackEm.elements.MoleToHit;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import whackEm.persistent.GameState;
import whackEm.ui.EndScreen;
import whackEm.ui.PauseButton;
import whackEm.ui.PauseScreen;

public class WhackEmPanel extends SurfaceView implements SurfaceHolder.Callback {

	private static final String TAG = WhackEmPanel.class.getSimpleName();

	private WhackEmThread thread;
	private Context context = null;
	public static final int numMoles = 9;

	public static ArrayList<Bitmap> rabbitComingAnimation = new ArrayList<Bitmap>();
	public static ArrayList<Bitmap> rabbitDazedAnimation = new ArrayList<Bitmap>();
	public static ArrayList<Bitmap> sqrlComingAnimation = new ArrayList<Bitmap>();
	public static ArrayList<Bitmap> sqrlDazedAnimation = new ArrayList<Bitmap>();
	public static ArrayList<Bitmap> staticBlueClockAnimation = new ArrayList<Bitmap>();
	public static Bitmap headSquirrel, headRabbit;
	public Bitmap touchScreenToContinue;	
	public Bitmap pauseButtonBitmap, closeButtonBitmap, playButtonBitmap;

	private ArrayList<Mole> moles = new ArrayList<Mole>();
	private Bitmap backGround;
	private int pickedMole = 0;
	private int maxLevel = 500;
	private int minLevel = 1;
	public int level; // game level	
	private int levelDelay = 1000;
												// next mole to come
	private long gameTime;	
	private int lives;
	private GameState gs;
	private MoleToHit moleToHit;
	private BlueClock clock;
	public float scale = 0;
	private GameTimer gameTimer = null;

	private Random r = new Random();
	private PauseButton pauseButton;
	private float widthProportion, heightProportion;

	private long lastMoleTime = 0; // time the last mole came out
	private WhackEmActivity whackEmActivity;	
	private PauseScreen pauseScreen;
	private Resources resources;
	private EndScreen endScreen;
	private boolean gameFinished = false;
	private boolean levelPassed = false;
	

	

	WhackEmPanel(Context c, float screenWidth, float screenHeight, float density, GameState gs) {
		super(c);
		this.context = c;
		this.whackEmActivity = (WhackEmActivity) c;
		scale = density / 1.5f;
		this.gs = gs;
		backGround = BitmapFactory.decodeResource(getResources(),
				R.drawable.background);
		setProportions(screenWidth, screenHeight, backGround);
		getHolder().addCallback(this);
		backGround = scaleBitmaps(backGround);
		// create the game loop thread
		thread = new WhackEmThread(getHolder(), this);
		setFocusable(true);
		// Generate Random Numbers for molethis.
		pickedMole = r.nextInt(8);
		resources = context.getResources();
		gameTime = gs.timer;
		lives = gs.lives;
	}

	public void increaseLevel(boolean up) {
		if (up) {
			if (level < maxLevel)
				level++;
		} else if (level > minLevel)
			level--;
		gs.level = level;
		if (level <= 4)
			levelDelay = 1000;		
		else if (level <20)
			levelDelay = 800 - level*10;
		else 
			levelDelay = 400;
		gs.setGameTimer();
		gs.setMoleHitCounter(0);
	}

	public ArrayList<Bitmap> loadMoleComingAnimation(String prefix, int nframes) {
		ArrayList<Bitmap> tempBitmapList = new ArrayList<Bitmap>();

		for (int x = 10000; x <= nframes + 10000; x++) {
			String name = prefix + x;
			Log.d(TAG, "loading animation frame: " + name);
			int res_id = resources.getIdentifier(name, "drawable",
					context.getPackageName());
			tempBitmapList.add(scaleBitmaps(BitmapFactory.decodeResource(
					resources, res_id)));
		}
		for (int x = (10000 + nframes); x >= 10000; x--) {
			String name = prefix + x;
			// Log.d(TAG, "loading animation frame: " + name);
			int res_id = resources.getIdentifier(name, "drawable",
					context.getPackageName());
			tempBitmapList.add(scaleBitmaps(BitmapFactory.decodeResource(
					resources, res_id)));
		}
		return tempBitmapList;
	}

	public ArrayList<Bitmap> loadDazeAnimation(String prefix, int nframes) {
		ArrayList<Bitmap> tempBitmapList = new ArrayList<Bitmap>();
		for (int x = 10000; x <= nframes + 10000; x++) {
			String name = prefix + x;
			// Log.d(TAG, "loading animation frame: " + name);
			int res_id = resources.getIdentifier(name, "drawable",
					context.getPackageName());
			tempBitmapList.add(scaleBitmaps(BitmapFactory.decodeResource(
					resources, res_id)));
		}
		return tempBitmapList;
	}

	public ArrayList<Bitmap> loadClockAnimations(String prefix, int nframes) {
		ArrayList<Bitmap> tempBitmapList = new ArrayList<Bitmap>();
		for (int x = 100; x <= nframes + 100; x++) {
			String name = prefix + x;
			// Log.d(TAG, "loading animation frame: " + name);
			int res_id = resources.getIdentifier(name, "drawable",
					context.getPackageName());
			Log.d(TAG, "loading:" + name);
			Bitmap b = BitmapFactory.decodeResource(resources, res_id);
			tempBitmapList.add(scaleBitmaps(b));
		}
		return tempBitmapList;
	}

	public void loadAnimations() {
		rabbitComingAnimation = loadMoleComingAnimation("rco", 15);
		rabbitDazedAnimation = loadDazeAnimation("rdz", 30);
		sqrlComingAnimation = loadMoleComingAnimation("sco", 15);
		sqrlDazedAnimation = loadDazeAnimation("sdz", 30);
		staticBlueClockAnimation = loadClockAnimations("bw", 30);
		headRabbit = scaleBitmaps(BitmapFactory.decodeResource(resources,
				R.drawable.headrabbit));
		headSquirrel = scaleBitmaps(BitmapFactory.decodeResource(resources,
				R.drawable.headsquirrel));
		this.pauseButtonBitmap = scaleBitmaps(BitmapFactory.decodeResource(
				resources, R.drawable.pausebutton));
		this.closeButtonBitmap = scaleBitmaps(BitmapFactory.decodeResource(
				resources, R.drawable.closebutton));
		this.playButtonBitmap = scaleBitmaps(BitmapFactory.decodeResource(
				resources, R.drawable.playbutton));
		this.touchScreenToContinue = scaleBitmaps(BitmapFactory.decodeResource(
				resources,R.drawable.touch_the_screen_to_continue));

	}

	public void createMolesObjects() {
		for (int i = 0; i < numMoles; i++) {
			Mole mole = new Mole(i, 25, this,gs);
			moles.add(mole);
		}
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		Log.d(TAG, "sufraceChanged");
	}

	public void surfaceCreated(SurfaceHolder holder) {
		if (moles.size() == 0) { // Se esta rodando a primeira vez
					
		    gameTimer = new GameTimer(context, gameTime * 1000, scale,this);
            loadAnimations();
			createMolesObjects();
			endScreen = new EndScreen(touchScreenToContinue, this);
			pauseScreen = new PauseScreen(closeButtonBitmap, playButtonBitmap, this);			
			moleToHit = new MoleToHit(15, 25, this,gs);
			pauseButton = new PauseButton(pauseButtonBitmap, scale, this);

			clock = new BlueClock(25, scale, this,gs);
			this.gameFinished = false;
		}
		if (WhackEmActivity.FLAG_isPaused) {
			Log.d(TAG, "isPaused");
			pauseGame();
			WhackEmActivity.FLAG_isPaused = false;

		}
		Log.d(TAG, "surfaceCreated");
		if (thread.getState() == Thread.State.TERMINATED) {
			Log.d(TAG, "new thread");
			thread = new WhackEmThread(getHolder(), this);
			thread.setRunning(true);
			thread.start();
		} else {
			thread.setRunning(true);
			thread.start();
		}

	}

	public void update() {
		if (!gameFinished) {	
			// make the moles come out in the time defined by Level
			long time = (System.currentTimeMillis() - lastMoleTime);
			if (time >= levelDelay) { // the delay time has passed. set next mole
				pickedMole = r.nextInt(8);
				// Testar todas as molas saindo
				// for (Mole mole : moles){
				// if (!mole.isAnimated())
				// mole.setComingOut(true, 4);
				// }
				// uma mola saindo por vez
				while (moles.get(pickedMole).isAnimated()) {
					pickedMole = r.nextInt(8);
				}
				lastMoleTime = System.currentTimeMillis();
				moles.get(pickedMole).setComingOut(true, level);
			}
	
			
			for (Mole mole : moles) {
				mole.update(System.currentTimeMillis());
			}
			moleToHit.update(System.currentTimeMillis());
			clock.update(System.currentTimeMillis());
			gameTimer.update(System.currentTimeMillis());
		}
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		while (retry) {
			try {
				thread.join();
				retry = false;
			} catch (InterruptedException e) {
				// try again shutting down the thread

			}
		}
	}

	public void pauseGame() {
		thread.pauseGame();
		Canvas canvas = getHolder().lockCanvas();
		render(canvas);
		pauseScreen.draw(canvas);
		getHolder().unlockCanvasAndPost(canvas);
	}

	public boolean isGamePaused() {
		return thread.isPaused();
	}

	public void unpauseGame() {
		Canvas canvas = getHolder().lockCanvas();
		render(canvas);
		getHolder().unlockCanvasAndPost(canvas);
		thread.unpauseGame();
	}

	public boolean onTouchEvent(MotionEvent motionEvent) {
		int action = motionEvent.getAction();
		float x, y;
		switch (action & MotionEvent.ACTION_MASK) {
		case MotionEvent.ACTION_DOWN:
			Log.d(TAG,
					"Coords: x=" + motionEvent.getX() + ",y="
							+ motionEvent.getY());
			x = motionEvent.getX();
			y = motionEvent.getY();
			if (gameFinished)
					endScreen.handleActionDown(x, y);
			else if (isGamePaused())
				pauseScreen.handleActionDown(x, y);			
			else {
				for (Mole mole : moles)
					mole.handleActionDown(x, y);
				pauseButton.handleActionDown(x, y);
				clock.handleActionDown(x,y);
			}
			break;
		// case MotionEvent.ACTION_POINTER_DOWN:
		// Log.d(TAG, "Coords: x=" + motionEvent.getX() + ",y=" +
		// motionEvent.getY());
		// x = motionEvent.getX();
		// y = motionEvent.getY();
		// for (Mole mole : moles)
		// mole.handleActionDown(x, y);
		// pauseButton.handleActionDown(x, y);
		// break;
		default:
			break;
		}
		return true;
	}

	public void stopPLaying() { // the application will be put in background
		thread.setRunning(false);
		// ((Activity)context).finish();
	}

	public void stopPlayingAndKillActivity() {
		whackEmActivity.userExitedGame = true;
		thread.setRunning(false);
		Intent i = new Intent(context, StatsActivity.class);
		Bundle extras = new Bundle();
		
		
		//TODO add the extras
        extras.putInt(StatsActivity.LIVES,lives);
        extras.putInt(StatsActivity.CORRECT_MOLES,gs.rightMolesCounter);
        extras.putInt(StatsActivity.WRONG_MOLES,gs.wrongMolesCounter);
        //levelMoles = extras.getInt(LEVEL_MOLES);
        //extras.putInt(StatsActivity.CLOCKS);
        extras.putBoolean(StatsActivity.COMPLETED,levelPassed);
        //extras.putLong(StatsActivity.TIME_LEFT,gameTimer.g);
        extras.putInt(StatsActivity.MAX_LIVES,gs.maxLives);
        i.putExtras(extras);
		whackEmActivity.startActivity(i);
		whackEmActivity.finish();
	}

	protected void render(Canvas canvas) {
		canvas.drawBitmap(backGround, 0, 0, null);
		gameTimer.drawTimer(canvas);
		for (Mole mole : moles)
			mole.drawMole(canvas);
		gs.draw(canvas);
		moleToHit.drawMole(canvas);
		clock.drawClock(canvas);
		pauseButton.draw(canvas);
		if (this.gameFinished)
			endScreen.draw(canvas);
	}

	// Set the proportions for scaling in multiple devices
	public void setProportions(float screenWidth, float ScreenHeight,
			Bitmap background) {

		this.heightProportion = ScreenHeight / background.getHeight();
		this.widthProportion = screenWidth / background.getWidth();

	}

	/**
	 * converte medidas que nao foram convertidas pelo so ainda
	 * 
	 * @param x
	 * @return
	 */
	public float convertX(float x) {
		return x * scale * widthProportion;
	}

	public float convertY(float y) {
		return y * scale * heightProportion;
	}

	/**
	 * converte medidas que ja foram convertidas uma vez pelo SO, drawables.
	 * 
	 * @param x
	 * @return
	 */
	public float convertXforDrawable(float x) {
		return x * widthProportion;

	}

	public float convertYforDrawable(float y) {
		return y * heightProportion;

	}

	// nao escala os drawables duas vezes por que ele ja esta escalado

	public Bitmap scaleBitmaps(Bitmap bitmap) {
		Bitmap out = Bitmap.createScaledBitmap(bitmap,
				(int) (bitmap.getWidth() * widthProportion),
				(int) (bitmap.getHeight() * heightProportion), false);
		return out;
	}
	
	public void updateTimer(float time, boolean increase) { 
		if (increase)
			gameTimer.increaseTimer(time);
		else
			gameTimer.decreaseTimer(time);
		
	}

	public void gameEndedOnTimerOrLives(boolean gameEndedOnTimer) {
		if (gameEndedOnTimer)
			levelPassed = true;
		this.gameFinished = true;		
		thread.setRunning(false);
		
	}

	
	public void addLife(){
		this.lives++;
		gs.lives = this.lives;
	}
	
	public void removeLife(){
		this.lives--;
		gs.lives = this.lives;
		if (this.lives <= 0)
			gameEndedOnTimerOrLives(false);
			
	}

}
